# 导包
import tornado.web

# 服务器
from tornado import httpserver

# 导入基础类
from base import BaseHandler

# 导入数据库操作类
from db import database,User,myser,MyMongo

# 异步执行库
import peewee_async
import hashlib

import json

from tools import ret_json,send_mail,MyJwt

from playhouse.shortcuts import model_to_dict

from test_desgin import SimpleFactory


import random
import datetime
import re

import pytz
# 设置时区
tzinfo = pytz.timezone('Asia/Shanghai')

import requests

def print_model(model):
    return json.dumps(model_to_dict(model), indent=4, sort_keys=True, default=str,ensure_ascii=False)

# 绘图库

from PIL import ImageDraw
from PIL import Image

# io库
import io

# 时间模块
import time


import base64
import hmac
from hashlib import sha256

import urllib

import os


# 文件上传接口
class Upload(BaseHandler):

	async def post(self):

		# 获取文件
		file = self.request.files["file"]

		id = self.get_argument("id",None)

		filename = ""

		for meta in file:

			# 文件名
			filename = meta["filename"]

			# 获取当前时间戳
			mytime = str(int(time.time()))

			# 获取前缀和后缀
			last_file = os.path.splitext(filename)[-1]
			front_file = os.path.splitext(filename)[0]

			newfilename = front_file+"_"+mytime+last_file

			# 写文件
			with open('./static/'+newfilename,"wb") as f:
				f.write(meta["body"])

		if id:

			# 修改头像
			user = await self.application.objects.get(User,id=id)
			user.img = "http://localhost:8888/static/%s" % newfilename

			# 异步
			await self.application.objects.update(user)

		return self.write(ret_json({"code":200,"msg":"文件上传成功","filename":newfilename}))

# 定义图片文件流验证码
class MyCode(BaseHandler):

	async def get(self):

		# 定义画布大小
		img_size = (150,60)

		# 颜色种类对象
		image = Image.new("RGB",img_size,'black')

		# 定义画笔对象
		draw = ImageDraw.Draw(image,'RGB')

		# 定义验证码内容
		source = "0123456789"

		# 定义验证码容器
		code_str = ""

		# 动态生成验证码
		for x in range(4):

			# 获取随机字符串
			tmp_num = random.randrange(len(source))

			# 获取随机字符串
			random_str = source[tmp_num]

			# 累加到容器
			code_str += random_str

			# 将随机字符绘制
			draw.text((10+30*x,20),random_str,"red")

		# 文件流对象
		buf = io.BytesIO()
		# 保存绘制的图片
		image.save(buf,'png')
		# 声明头部信息
		self.set_header('Content-Type','image/png')
		# 返回图片
		return self.write(buf.getvalue())




# 用户详情接口
class UserInfo(BaseHandler):

	async def get(self):

		id = self.get_argument("id",None)

		# 查询
		try:

			user = await self.application.objects.get(User,id=id)

		except Exception as e:

			return self.write(ret_json({}))
		# 序列器
		user = myser(user)
		print(user)
		return self.write(ret_json(user))

		#return self.write(ret_json({"username":user.username,"id":user.id,""}))




# 获取三方登录的地址
class GetUrl(BaseHandler):

	async def get(self):

		gitee_url = SimpleFactory.get_url("gitee")

		dingding_url = SimpleFactory.get_url("dingding")

		weibo_url = SimpleFactory.get_url("weibo")

		return self.write({"gitee":gitee_url,"dingding":dingding_url,"weibo":weibo_url})

# dingding 回跳接口
class DingdingBack(BaseHandler):

	async def get(self):

		code = self.get_argument("code",None)

		# 构造签名

		# 获取当前时间戳
		t = time.time()

		# 转换毫秒时间戳
		timestamp = str(int(round(t * 1000)))

		appSecret = "DTQdFCGyW9dn_UWDe1INSETnvh3DUvo7MHnxM0kzYBWtfDu7aa-zGO3b3ZP1-0XN"

		# 构造签名

		signature = base64.b64encode(
			hmac.new(appSecret.encode("utf-8"),
			timestamp.encode("utf-8"),
			digestmod = sha256).digest()
		)

		# 定义载荷
		payload = {'tmp_auth_code':code}

		# 定义头部信息
		headers = {"Content-Type":"application/json"}
		res = requests.post('https://oapi.dingtalk.com/sns/getuserinfo_bycode?signature=' +urllib.parse.quote(signature.decode("utf-8")) + "&timestamp=" +timestamp + "&accessKey=ding4heilahraihho2sw",data=json.dumps(payload),headers=headers)

		print(res.text)

		res = res.json()

		username = res["user_info"]["nick"]

		# 异步查询
		user = await self.application.objects.execute(User.select().where(User.username==username))

		try:
			user = user[0]

		except Exception as e:

			user = await self.application.objects.create(User,username=username,password='',state=1,email=str(random.randint(1,1000)))

		# 重定向操作
		self.redirect("http://localhost:8080/mystation/?username=%s&id=%s" % (user.username,user.id))

		return self.write(signature)


# 微博回跳
class WeiBoBack(BaseHandler):

	async def get(self):

		code = self.get_argument("code",None)

		res = SimpleFactory.get_info(name="weibo",code=code)

		username = res[0]
		img = res[1]

		user = await SimpleFactory.find_one(self.application.objects,User,username)
		# 序列化
		user = [myser(x) for x in user]

		if user:
			username = user[0]["username"]
			id = user[0]["id"]
		else:	
			# 入库
			user = SimpleFactory.insert(Model=User,username=username,img=img)
			username = user.username
			id = user.id

		self.redirect("http://localhost:8080/mystation/?username=%s&id=%s" % (username,id))


# code交换token
class GiteeBack(BaseHandler):

	async def get(self):

		code = self.get_argument("code",None)
		token = SimpleFactory.get_token(code)
		# 最后一步，交换用户信息
		res = SimpleFactory.get_info(name="gitee",token=token)
		username = res[0]
		avatar_url = res[1]

		# 入库操作
		# 查询是否首次用gitee登录

		# 异步查询
		user = await self.application.objects.execute(User.select().where(User.username==username))

		try:
			user = user[0]
		except Exception as e:

			user = await self.application.objects.create(User,username=username,password='',state=1,email=str(random.randint(1,1000)),img=avatar_url)

		# 重定向操作

		self.redirect("http://localhost:8080/mystation/?username=%s&id=%s" % (user.username,user.id))

# 用户视图
class UserHandler(BaseHandler):

	def make_password(self,mypass):

		md5 = hashlib.md5()

		# 转码
		sign_utf8 = str(mypass+"123").encode(encoding="utf-8")
		md5.update(sign_utf8)

		return md5.hexdigest()


	# 账号密码登录
	async def get(self):

		# 接收参数
		username = self.get_argument("username",None)

		password = self.get_argument("password",None)

		if username is None or username == "":

			return self.write(ret_json({'code':403,"msg":"用户名不能为空"}))

		if password is None or password == "":

			return self.write(ret_json({'code':403,"msg":"密码不能为空"}))

		# 异步查询
		user = await self.application.objects.execute(User.select().where((User.username==username) & (User.password==self.make_password(password))))

		try:
			user = user[0]

			# 加密操作
			myjwt = MyJwt()
			token = myjwt.encode({"id":user.id})

			return self.write(ret_json({'code':200,'msg':"登录成功","username":user.username,"id":user.id,"token":token}))

		except Exception as e:

			return self.write(ret_json({"code":403,"msg":"您的用户名或者密码有误"}))


	# 注册
	async def post(self):

		# 接收参数
		username = self.get_argument("username",None)

		password = self.get_argument("password",None)


		# 非空验证

		if username is None or username == "":

			return self.write(ret_json({'code':403,"msg":"用户名不能为空"}))

		if password is None or password == "":

			return self.write(ret_json({'code':403,"msg":"密码不能为空"}))

		# 合法性验证
		# 账号4-10 只能由数字字母下划线组成
		# 密码6-18 只能由字母开头，并且数字，字母下划线组成

		# 虚位密码
		# 密码必须6位
		# password = pasword[-6:]

		# 321123456
		# 321123456

		# 正则
		result_username = re.compile(r"^\w{4,10}$")
		result_password = re.compile(r"^[a-zA-Z]\w{5,17}$")

		# 开始匹配
		if result_username.match(username) is None:

			return self.write(ret_json({'code':403,"msg":"您的用户名不合法"}))

		if result_password.match(password) is None:

			return self.write(ret_json({'code':403,"msg":"您的密码不合法"}))





		ret = {"code":200,"msg":"注册成功"}

		# 入库操作
		try:
			user = await self.application.objects.create(User,username=username,password=self.make_password(password),state=1,email=str(random.randint(1,1000)))
		except Exception as e:
			ret = {"code":403,"msg":"您的账户已经被占用"}

			# user = User.get(id=2)

			# data = print_model(user)

			# ss = {"data":data,"msg":"你好"}

			return self.write(ret_json(ret))

		return self.write(ret_json(ret))


# 继承用户接口
class PhoneLogin(UserHandler):

	async def get(self):

		# 获取手机号

		phone = self.get_argument("phone",None)

		# 获取用户输入验证码

		code = self.get_argument("code",None)


		# 通过phone获取mongo中验证码

		mymongo = MyMongo()

		mongo_code = mymongo.find_one({"phone":phone})

		if mongo_code is None:

			return self.write(ret_json({"code":403,"msg":"您的验证码已经过期"}))

		if int(code) == int(mongo_code["code"]):


			# 是否曾经登录过

			user = await self.application.objects.execute(User.select().where(User.phone==phone))

			#print(user[0].phone)

			try:

				# 查询操作
				user = user[0]
				return self.write(ret_json({"code":200,"msg":"登录成功","id":user.id,"username":user.phone}))

			except Exception as e:

				# 入库操作
				user = await self.application.objects.create(User,username=phone,password="",state=1,phone=phone,email=str(random.randint(1,1000)))

				return self.write(ret_json({"code":200,"msg":"登录成功","id":user.id,"username":user.phone}))


		else:

			return self.write(ret_json({"code":403,"msg":"您的验证码输入有误"}))




# 回跳接口
class EmailBack(UserHandler):

	async def get(self):

		# 获取参数
		id = self.get_argument("id",None)

		if id is None or id == "":

			return self.write(ret_json({"code":403,"msg":"用户id不能为空"}))

		# 解密操作
		myjwt = MyJwt()
		try:
			id = myjwt.decode(id)
		except Exception as e:
			return self.write(ret_json({"code":403,"msg":"请不要篡改用户信息"}))

		id = id["id"]

		# 异步查询
		try:
			user = await self.application.objects.get(User,id=id)
		except Exception as e:
			return self.write(ret_json({"code":403,"msg":"该用户不存在"}))

		# 判断
		if user.state == 0:

			# 修改状态为1
			user.state = 1
			await self.application.objects.update(user)

			return self.write(ret_json({"code":200,"msg":"激活成功"}))

		else:

			return self.write(ret_json({"code":200,"msg":"您已经激活过，请不要重复激活"}))


# 邮箱激活接口
class EmailActive(UserHandler):


	# 重写post，入库逻辑
	async def post(self):

		email = self.get_argument("email",None)

		# 非空验证
		if email == None or email == "":

			return self.write(ret_json({"code":403,"msg":"邮箱不能为空"}))

		# 合法性验证

		# qq号@qq.com
		# 5-11位
		# @qq.com结尾
		# 不能以0开头

		result_email = re.compile(r'^[1-9][0-9]{4,10}@qq\.com$')

		if result_email.match(email) is None:

			return self.write(ret_json({"code":403,"msg":"邮箱不合法"}))


		# 入库操作
		try:
			user = await self.application.objects.create(User,email=email,username=str(random.randint(1,1000)))
			#User.create(email=email)
		except Exception as e:
			return self.write(ret_json({"code":403,"msg":"请换一个邮箱"}))


		# 查询操作
		#user = await self.application.objects.get(User,email=email)


		# 发送邮件
		#await send_mail("123","123","123",user.id)




		return self.write(ret_json({"code":200,"msg":"发送邮件成功"}))




# 邮箱验证码发送
class EmailCode(EmailActive):


	def get_code(self):

		mystr = ""
		for x in range(4):
			mystr += str(random.randint(0,9))
		return mystr		

	async def post(self):

		email = self.get_argument("email",None)

		# 将生成验证码入库

		mycode = self.get_code()

		mymongo = MyMongo()

		mymongo.insert({"code":mycode,"datetime":tzinfo.localize(datetime.datetime.now()),"email":email})


		return self.write(ret_json({"code":mycode}))













